package org.ouwh.oowiki.ctrl;

import java.util.ArrayList;
import java.util.Stack;

import javax.servlet.http.HttpServletRequest;

import org.ouwh.fw.model.module.Module;
import org.ouwh.fw.util.xml.Node;
import org.ouwh.oowiki.http.MyException;
import org.ouwh.oowiki.http.MyRequest;
import org.ouwh.oowiki.http.MyResponse;

public abstract class AbstractController extends Module implements IController {

	protected abstract MyResponse invoke(MyRequest request) throws MyException;

	private ArrayList<IRoundControllerInterceptor> roundControllerInterceptors = new ArrayList<IRoundControllerInterceptor>();

	private ArrayList<IBeforeControllerInterceptor> beforeControllerInterceptors = new ArrayList<IBeforeControllerInterceptor>();

	private ArrayList<IAfterControllerInterceptor> afterControllerInterceptors = new ArrayList<IAfterControllerInterceptor>();

	private Stack<IRoundControllerInterceptor> roundInterceptorStack = new Stack<IRoundControllerInterceptor>();

	protected String controllerName;
	
	protected HttpServletRequest rawRequest;

	@Override
	public void addRoundInterceptor(IRoundControllerInterceptor interceptor) {
		roundControllerInterceptors.add(interceptor);
	}

	@Override
	public void removeRoundInterceptor(IRoundControllerInterceptor interceptor) {
		roundControllerInterceptors.remove(interceptor);
	}

	@Override
	public void addAfterInterceptor(IAfterControllerInterceptor interceptor) {
		afterControllerInterceptors.add(interceptor);
	}

	@Override
	public void addBeforeInterceptor(IBeforeControllerInterceptor interceptor) {
		beforeControllerInterceptors.add(interceptor);
	}

	@Override
	public void removeAfterInterceptor(IAfterControllerInterceptor interceptor) {
		afterControllerInterceptors.remove(interceptor);
	}

	@Override
	public void removeBeforeInterceptor(IBeforeControllerInterceptor interceptor) {
		beforeControllerInterceptors.remove(interceptor);
	}

	@Override
	public String getControllerName() {
		return controllerName;
	}

	@Override
	public void setControllerName(String controllerName) {
		this.controllerName = controllerName;
	}

	@Override
	public void init(Node node) throws Exception {
		super.init(node);
		setControllerName(getId());

		Node before = node.getChild("before", 1);
		if (null != before) {
			Node[] befores = before.getChildren();
			for (int i = 0; i < befores.length; i++) {
				String className = befores[i].getXmlType();
				Class<?> clazz = Class.forName(className);
				IBeforeControllerInterceptor in = (IBeforeControllerInterceptor) clazz.newInstance();
				addBeforeInterceptor(in);
				in.setControllerName(getControllerName());
			}
		}

		Node round = node.getChild("round", 1);
		if (null != round) {
			Node[] rounds = round.getChildren();
			for (int i = 0; i < rounds.length; i++) {
				String className = rounds[i].getXmlType();
				Class<?> clazz = Class.forName(className);
				IRoundControllerInterceptor in = (IRoundControllerInterceptor) clazz.newInstance();
				addRoundInterceptor(in);
				in.setControllerName(getControllerName());
			}
		}

		Node after = node.getChild("after", 1);
		if (null != after) {
			Node[] afters = after.getChildren();
			for (int i = 0; i < afters.length; i++) {
				String className = afters[i].getXmlType();
				Class<?> clazz = Class.forName(className);
				IAfterControllerInterceptor in = (IAfterControllerInterceptor) clazz.newInstance();
				addAfterInterceptor(in);
				in.setControllerName(getControllerName());
			}
		}
	}

	@Override
	public MyResponse execute(MyRequest request) throws MyException {
		this.rawRequest = request.getRawRequest();
		for (IBeforeControllerInterceptor interceptor : beforeControllerInterceptors) {
			interceptor.beforeController(request);
		}
		for (IRoundControllerInterceptor interceptor : roundControllerInterceptors) {
			interceptor.beforeController(request);
			roundInterceptorStack.push(interceptor);
		}
		MyResponse response = invoke(request);
		while (!roundInterceptorStack.empty()) {
			IRoundControllerInterceptor interceptor = roundInterceptorStack.pop();
			interceptor.afterController(request, response, null);
		}
		for (IAfterControllerInterceptor interceptor : afterControllerInterceptors) {
			interceptor.afterController(request, response, null);
		}
		return response;
	}

}
